package com.codedancer.campus.manager.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.codedancer.campus.common.exception.BusinessException;
import com.codedancer.campus.common.utils.CodecUtils;
import com.codedancer.campus.common.utils.RedisUtil;
import com.codedancer.campus.common.utils.SecurityUtils;
import com.codedancer.campus.common.utils.UUIDGenerator;
import com.codedancer.campus.manager.service.IAdminService;
import com.codedancer.campus.manager.service.bo.admin.AdminAddOrUpdateBo;
import com.codedancer.campus.manager.service.bo.admin.AdminLoginBo;
import com.codedancer.campus.manager.service.bo.admin.AdminPageSearchBo;
import com.codedancer.campus.manager.service.vo.admin.AdminInfoVo;
import com.codedancer.campus.manager.service.vo.admin.AdminPageVo;
import com.codedancer.campus.manager.service.vo.menu.MenuVO;
import com.codedancer.campus.mapper.AdminMapper;
import com.codedancer.campus.mapper.AdminRoleMapper;
import com.codedancer.campus.mapper.MenuMapper;
import com.codedancer.campus.mapper.RoleMapper;
import com.codedancer.campus.mapper.RoleMenuMapper;
import com.codedancer.campus.po.Admin;
import com.codedancer.campus.po.AdminRole;
import com.codedancer.campus.po.Menu;
import com.codedancer.campus.po.Role;
import com.codedancer.campus.po.RoleMenu;
import com.codedancer.campus.qo.admin.AdminPageSearchQo;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import javax.security.auth.message.AuthException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class AdminServiceImpl implements IAdminService {

    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    @Autowired
    private RoleMenuMapper roleMenuMapper;
    @Autowired
    private MenuMapper menuMapper;
    @Autowired
    private RedisUtil redisUtil;
    /**
     * 存放验证码RedisKey
     */
    @Value("${start.campus.redis.captcha.key}")
    private String CAPTCHA_KEY;

    /**
     * 管理员登录
     *
     * @param adminLoginBo
     * @return
     */
    @Override
    public String login(AdminLoginBo adminLoginBo)
        throws UnsupportedEncodingException, NoSuchAlgorithmException {
        // 校验验证码
        if (!redisUtil.isExist(CAPTCHA_KEY + adminLoginBo.getCaptchaKey())) {
            log.info("验证码Key：{}", CAPTCHA_KEY + adminLoginBo.getCaptchaKey());
            throw new BusinessException("验证码已失效");
        }
        String captchaCode = redisUtil.getStringValue(CAPTCHA_KEY + adminLoginBo.getCaptchaKey());
        if (!captchaCode.equals(adminLoginBo.getCaptchaCode())) {
            throw new BusinessException("验证码错误");
        }
        // 校验通过开始
        Admin admin = adminMapper.findByColumn("login_name", adminLoginBo.getLoginName())
            .orElseThrow(() -> new BusinessException("用户名或密码错误"));
        // 校验密码
        String password = CodecUtils.md5Hex(adminLoginBo.getPassword(), admin.getSalt());
        if (!password.equals(admin.getPassword())) {
            throw new BusinessException("用户名或密码错误");
        }
        if (admin.getDisabled()) {
            throw new BusinessException("已禁用");
        }
        // 全部通过删除redis中验证码
        redisUtil.delete(CAPTCHA_KEY + adminLoginBo.getCaptchaKey());
        // 生成token
        return SecurityUtils.genToken(admin.getUuid(), admin.getPassword());
    }

    /**
     * 获取用户信息
     *
     * @param currentLoginUuid
     * @return
     */
    @Override
    public AdminInfoVo currentUserInfo(String currentLoginUuid) throws AuthException {
        Admin admin = adminMapper.findById(currentLoginUuid)
            .orElseThrow(() -> new BusinessException("管理员不存在"));
        // 获取管理员角色
        AdminRole adminRole = adminRoleMapper.selectOneByColumn("admin_uuid", admin.getUuid());
        if (ObjectUtil.isEmpty(adminRole)) {
            throw new AuthException("管理员绑定角色不存在");
        }
        Role role = roleMapper.findById(adminRole.getRoleUuid())
            .orElseThrow(() -> new AuthException("角色不存在"));
        AdminInfoVo adminInfoVo = BeanUtil.copyProperties(admin, AdminInfoVo.class);
        adminInfoVo.setEncode(role.getEncode());
        adminInfoVo.setRoleName(role.getName());
        List<MenuVO> menuVOS = new ArrayList<>();
        // 获取角色菜单
        List<RoleMenu> roleMenus = roleMenuMapper.selectListByColumn("role_uuid", role.getUuid());
        for (RoleMenu roleMenu : roleMenus) {
            Menu menu = menuMapper.selectById(roleMenu.getMenuUuid());
            MenuVO menuVO = BeanUtil.copyProperties(menu, MenuVO.class);
            // 判断是否存在儿子
            if (menuMapper.existsByColumn("parent_uuid", menu.getUuid())) {
                menuVO.setHasChildren(true);
            }
            menuVOS.add(menuVO);
        }
        menuVOS = menuVOS.stream().sorted(Comparator.comparing(MenuVO::getSort))
            .collect(Collectors.toList());
        adminInfoVo.setMenuVOS(menuVOS);
        return adminInfoVo;
    }

    /**
     * 分页查询管理员
     *
     * @param adminPageSearchBo
     * @return
     */
    @Override
    public IPage<AdminPageVo> page(AdminPageSearchBo adminPageSearchBo) {
        AdminPageSearchQo adminPageSearchQo = BeanUtil.copyProperties(adminPageSearchBo,
            AdminPageSearchQo.class);
        IPage<Admin> adminIPage = adminMapper.page(
            new Page<Admin>(adminPageSearchBo.getPage(), adminPageSearchBo.getSize()),
            adminPageSearchQo);
        List<AdminPageVo> adminPageVos;
        IPage<AdminPageVo> adminPageVoIPage = new Page<>();
        adminPageVos = adminIPage.getRecords().stream().map(admin -> {
            AdminPageVo adminPageVo = BeanUtil.copyProperties(admin, AdminPageVo.class);
            if (ObjectUtil.isNotEmpty(admin.getRole())) {
                adminPageVo.setRoleName(admin.getRole().getName());
                adminPageVo.setRoleUuid(admin.getRole().getUuid());
            }
            return adminPageVo;
        }).collect(Collectors.toList());
        adminPageVoIPage.setTotal(adminIPage.getTotal());
        adminPageVoIPage.setRecords(adminPageVos);
        return adminPageVoIPage;
    }

    /**
     * 添加管理员
     *
     * @param adminAddOrUpdateBo
     */
    @Override
    public void add(AdminAddOrUpdateBo adminAddOrUpdateBo) {
        if (!roleMapper.existsByUuId(adminAddOrUpdateBo.getRoleUuid())) {
            throw new BusinessException("角色不存在，请重新选择");
        }
        if (adminMapper.existsByColumn("login_name", adminAddOrUpdateBo.getLoginName())) {
            throw new BusinessException("登录名称已存在，请重新填写");
        }
        Admin admin = BeanUtil.copyProperties(adminAddOrUpdateBo, Admin.class);
        admin.setUuid(UUIDGenerator.getUUID());
        String salt = CodecUtils.generateSalt();
        String password = CodecUtils.md5Hex("123456", salt);
        admin.setSalt(salt);
        admin.setPassword(password);
        adminMapper.insert(admin);
        // 关联角色
        AdminRole adminRole = AdminRole.builder()
            .uuid(UUIDGenerator.getUUID())
            .adminUuid(admin.getUuid())
            .roleUuid(adminAddOrUpdateBo.getRoleUuid()).build();
        adminRoleMapper.insert(adminRole);
    }

    /**
     * 修改管理员
     *
     * @param adminAddOrUpdateBo
     */
    @Override
    public void update(AdminAddOrUpdateBo adminAddOrUpdateBo) {
        Admin admin = adminMapper.findById(adminAddOrUpdateBo.getUuid())
            .orElseThrow(() -> new BusinessException("管理员不存在"));
        if (admin.getDisabled()) {
            throw new BusinessException("管理员已被禁用，不能修改");
        }
        if (!roleMapper.existsByUuId(adminAddOrUpdateBo.getRoleUuid())) {
            throw new BusinessException("角色不存在，请重新选择");
        }
        if (!admin.getLoginName().equals(adminAddOrUpdateBo.getLoginName())) {
            if (adminMapper.existsByColumn("login_name", adminAddOrUpdateBo.getLoginName())) {
                throw new BusinessException("登录名称已存在，请重新填写");
            }
            admin.setLoginName(adminAddOrUpdateBo.getLoginName());
        }
        adminMapper.updateById(admin);
        AdminRole adminRole = adminRoleMapper.findByColumn("admin_uuid", admin.getUuid())
            .orElseThrow(() -> new BusinessException("管理员绑定的角色不存在"));
        adminRole.setRoleUuid(adminAddOrUpdateBo.getRoleUuid());
        adminRoleMapper.updateById(adminRole);
    }

    /**
     * 启用管理员
     *
     * @param uuid
     * @param currentLoginUuid
     */
    @Override
    public void enable(String uuid, String currentLoginUuid) {
        Admin admin = adminMapper.findById(uuid)
            .orElseThrow(() -> new BusinessException("管理员不存在"));
        AdminRole adminRole = adminRoleMapper.selectOneByColumn("admin_uuid", currentLoginUuid);
        Role role = roleMapper.selectById(adminRole.getRoleUuid());
        if (!role.getEncode().equals("superAdmin")) {
            throw new BusinessException("只能超级管理员才能启用");
        }
        if (currentLoginUuid.equals(uuid)) {
            throw new BusinessException("不能启用自己");
        }
        admin.setDisabled(false);
        adminMapper.updateById(admin);
    }

    /**
     * 禁用管理员
     *
     * @param uuid
     * @param currentLoginUuid
     */
    @Override
    public void disable(String uuid, String currentLoginUuid) {
        Admin admin = adminMapper.findById(uuid)
            .orElseThrow(() -> new BusinessException("管理员不存在"));
        AdminRole adminRole = adminRoleMapper.selectOneByColumn("admin_uuid", currentLoginUuid);
        Role role = roleMapper.selectById(adminRole.getRoleUuid());
        if (!role.getEncode().equals("superAdmin")) {
            throw new BusinessException("只能超级管理员才能禁用");
        }
        if (currentLoginUuid.equals(uuid)) {
            throw new BusinessException("不能禁用自己");
        }
        admin.setDisabled(true);
        adminMapper.updateById(admin);
    }

    /**
     * 删除管理员
     *
     * @param uuid
     */
    @Override
    public void delete(String uuid) {
        if (!adminMapper.existsByUuId(uuid)) {
            throw new BusinessException("管理员不存在");
        }
        adminMapper.deleteById(uuid);
    }
}
